package com.yc.starter.login.web;

import com.yc.starter.login.config.LoginProperties;
import com.yc.starter.login.dto.Result;
import com.yc.starter.vcode.web.VcodeDo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.SessionAttribute;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.Field;

/**
 * @author navy
 * @company 源辰信息
 * @date 2024/9/12
 * @email haijunzhou@hnit.edu.cn
 */
@RequestMapping("login")
@RestController
@Slf4j
public class LoginAction {
    @Autowired
    LoginProperties properties;

    @RequestMapping("props")
    LoginProperties props(){
        return properties;
    }

    @Autowired
    JdbcTemplate jdbc;
    @RequestMapping("login")
    Result login(String username,
                 String password,
                 HttpSession session) throws ClassNotFoundException {
        if(username==null || username.isBlank()){
            return new Result(-1, "请输入用户名",null);
        }
        if(password==null || password.isBlank()){
            return new Result(-2, "请输入密码",null);
        }
        String sql = "select * from %s where %s=? and %s=? or %s=?";
        sql = String.format(sql, properties.getUserTable(),
                properties.getNameColumn(),
                properties.getPwdColumn(),
                properties.getPwdColumn());
        String md5Pwd = DigestUtils.md5DigestAsHex((username + password).getBytes());
        log.debug("md5Pwd = " + md5Pwd);
//        Class<?> userClass = Class.forName(properties.getUserClassName());
        try {
            Object user = jdbc.queryForObject(sql,
                    new BeanPropertyRowMapper<>(properties.getUserClass()),
                    username, password, md5Pwd);
            session.setAttribute(properties.getSessionKey(), user);
            return new Result(1, "登录成功!",user);
        } catch ( DataAccessException e) {
            return new Result(-3, "用户名或密码错误!",null);
        }
    }

    @RequestMapping("myinfo")
    Result myinfo(HttpSession session){
        Object user = session.getAttribute(properties.getSessionKey());
        if(user == null){
            return new Result(-4, "未登录!",null);
        } else {
            return new Result(1, "已登录!",user);
        }
    }

    // 实现页面跳转
    @RequestMapping("logout")
    ModelAndView logout(ModelAndView mav,
                        HttpSession session){
        session.invalidate();
        mav.setViewName("redirect:/");
        return mav;
    }

    Result setPwd(HttpSession session){
        return null;
    }

    // 忘记密码
    @Autowired
    VcodeDo vcodeDo;

    @RequestMapping("forget")
    Result forget(String username, HttpSession session){
        if(username==null || username.isBlank()){
            return new Result(-1, "请输入用户名",null);
        }
        String sql = "select %s from %s where %s=?";
        sql = String.format(sql, properties.getEmailColumn(),
                properties.getUserTable(),
                properties.getNameColumn());
        try {
            String email = jdbc.queryForObject(sql,String.class,username);
            vcodeDo.email(session,email,"验证码",
                    "忘记密码的验证码是:");
            session.setAttribute("forgetUsername", username);
            return new Result(1, "验证码发送成功!",null);
        } catch ( DataAccessException e) {
            return new Result(-2, "用户名错误!",null);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @RequestMapping("resetPwd")
    Result resetPwd(String pwd, String rePwd,
                    @SessionAttribute String forgetUsername){
        if(pwd==null || pwd.isBlank()){
            return new Result(-1, "请输入新密码",null);
        }
        if(rePwd==null || rePwd.isBlank()){
            return new Result(-1, "请输入确认密码",null);
        }
        if(pwd.equals(rePwd) ==  false){
            return new Result(-1, "确认密码必须与新密码一致",null);
        }
        String sql = "update %s set %s = md5(concat(?,?)) where %s=?";
        sql = String.format(sql, properties.getUserTable(),
                properties.getPwdColumn(),
                properties.getNameColumn());
        int res = jdbc.update(sql, forgetUsername, pwd, forgetUsername);
        if(res == 1){
            return new Result(1, "密码重置成功!",null);
        } else {
            return new Result(-1, "密码重置失败, 请联系管理员!",null);
        }
    }

    @RequestMapping("regCode")
    Result regCode(String email,HttpSession session){
        if(email == null || email.isBlank()){
            return new Result(-1,"请输入邮箱",null);
        }
        String sql = "select count(1) from %s where %s=?";
        sql = String.format(sql,properties.getUserTable(),properties.getEmailColumn());
        int count = jdbc.queryForObject(sql,Integer.class,email);
        if(count > 0){
            return new Result(-1,"邮箱已存在",null);
        }
        try {
            vcodeDo.email(session,email,"验证码","注册的验证码是:");
            return new Result(1,"验证码已发送",null);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @RequestMapping("reg")
    Result register(String username,String password,String email){
        if(username == null || username.isBlank()){
            return new Result(-1,"用户名不能为空",null);
        }
        if(password == null || password.isBlank()){
            return new Result(-1,"密码不能为空",null);
        }
        if(email == null || email.isBlank()){
            return new Result(-1,"邮箱不能为空",null);
        }

        String sql = "select count(1) from %s where %s=?";
        sql = String.format(sql,properties.getUserTable(),properties.getNameColumn());
        int count = jdbc.queryForObject(sql,Integer.class,username);
        if(count > 0){
            return new Result(-1,"用户名已存在",null);
        }

        sql = "select count(1) from %s where %s=?";
        sql = String.format(sql,properties.getUserTable(),properties.getEmailColumn());
        count = jdbc.queryForObject(sql,Integer.class,email);

        if(count > 0){
            return new Result(-1,"邮箱已存在",null);
        }

        sql = "insert into %s(%s,%s,%s) values(?,md5(concat(?,?)),?)";
        sql = String.format(sql,properties.getUserTable(),properties.getNameColumn(),
               properties.getPwdColumn(),properties.getEmailColumn());
        int res = jdbc.update(sql,username,username,password,email);
        if(res == 1){
            return new Result(1,"注册成功",null);
        } else {
            return new Result(-1,"注册失败",null);
        }
    }
    @RequestMapping("/updatePwd")
    public Result updatePwd(String oldPwd,String pwd,String rePwd, HttpSession session) throws NoSuchFieldException, IllegalAccessException {
        Object user = session.getAttribute(properties.getSessionKey());
        if (user == null) {
            return new Result(-4, "用户未登录",null);
        }
        if (oldPwd == null || oldPwd.isBlank()) {
            return new Result(-3, "旧密码不能为空",null);
        }
        if (pwd == null || pwd.isBlank()) {
            return new Result(-3, "新密码不能为空",null);
        }
        if (rePwd == null || rePwd.isBlank()) {
            return new Result(-3, "确认密码不能为空",null);
        }
        if (!pwd.equals(rePwd)) {
            return new Result(-4, "两次密码不一致",null);
        }
        if (oldPwd.equals(pwd)) {
            return new Result(-5, "新密码不能与旧密码相同",null);
        }
        Class<?> clazz = properties.getUserClass();
        Field fp = clazz.getDeclaredField(properties.getPwdColumn());
        fp.setAccessible(true);
        String password = String.valueOf(fp.get(user));
        fp = clazz.getDeclaredField(properties.getNameColumn());
        fp.setAccessible(true);
        String name = String.valueOf(fp.get(user));
        String md5 = DigestUtils.md5DigestAsHex((name + oldPwd).getBytes());
        if (!password.equals(md5)) {
            return new Result(-6, "旧密码错误",null);
        }
        String sql = "update %s set %s=md5(concat(?,?)) where  %s = ?";
        sql = String.format(sql, properties.getUserTable(), properties.getPwdColumn(),
                properties.getPwdColumn());
        int result = jdbc.update(sql,  name, pwd, password);
        if (result > 0) {
            return new Result(200, "密码修改成功", null);
        }
        return new Result(-7, "密码修改失败",null);
    }

}
